package com.usian.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.usian.model.admin.dtos.NewsAuthDto;
import com.usian.model.common.dtos.PageResponseResult;
import com.usian.model.common.dtos.ResponseResult;
import com.usian.model.common.enums.AppHttpCodeEnum;
import com.usian.model.media.dtos.WmNewsDto;
import com.usian.model.media.dtos.WmNewsPageReqDto;
import com.usian.model.media.pojos.*;
import com.usian.utils.threadlocal.WmThreadLocalUtils;
import com.usian.wemedia.mapper.WmMaterialMapper;
import com.usian.wemedia.mapper.WmNewsMapper;
import com.usian.wemedia.mapper.WmNewsMaterialMapper;
import com.usian.wemedia.mapper.WmUserMapper;
import com.usian.wemedia.service.WmNewsService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Log4j2
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Value("${fileServerUrl}")
    private String fileServerUrl;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private KafkaTemplate kafkaTemplate;
    @Autowired
    private WmUserMapper wmUserMapper;

    public static final Short WM_NEWS_NONE_IMAGE = 0; //封面 无图
    public static final Short WM_NEWS_SINGLE_IMAGE = 1; //封面 单图
    public static final Short WM_NEWS_MANY_IMAGE = 3;   //封面 三图
    public static final Short WM_NEWS_TYPE_AUTO = -1;   //封面 自动
    public static final String WM_NEWS_TYPE_IMAGE = "image"; //提取文章内容中的图片标识
    public static final Integer WM_NEWS_CONTENT_REFERENCE=1 ;//主图引用

    @Override
    public ResponseResult findAll(WmNewsPageReqDto dto) {

        //1:校验参数
        if(dto==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();

        //2:封装查询条件   status   title like    channel_id    publish_time 区间查询    user_id 登录用户id  创建时间 倒序排
        QueryWrapper<WmNews> queryWrapper =new QueryWrapper<>();

        if(dto.getStatus()!=null){
            queryWrapper.lambda().eq(WmNews::getStatus,dto.getStatus());
        }
        if(StringUtils.isNotBlank(dto.getKeyword())){
            queryWrapper.lambda().like(WmNews::getTitle,dto.getKeyword());
        }
        if(dto.getChannelId() !=null){
            queryWrapper.lambda().eq(WmNews::getChannelId,dto.getChannelId());
        }
        if(dto.getBeginPubDate() !=null && dto.getEndPubDate()!=null){
            queryWrapper.lambda().between(WmNews::getPublishTime,dto.getBeginPubDate(),dto.getEndPubDate());
        }

        Integer userId = WmThreadLocalUtils.getUser().getId();
        if(userId !=null){
            queryWrapper.lambda().eq(WmNews::getUserId,userId);
        }
        queryWrapper.lambda().orderByDesc(WmNews::getCreatedTime);

        //3:分页结果
        Page page =new Page(dto.getPage(),dto.getSize());
        IPage ipage =page(page,queryWrapper);
        ResponseResult responseResult =new PageResponseResult(dto.getPage(),dto.getSize(),(int)ipage.getTotal());
        responseResult.setData(ipage.getRecords());
        responseResult.setHost(fileServerUrl);
        return responseResult;
    }

    @Override
    public ResponseResult submitNews(WmNewsDto dto, Short isSubmit) {

        //1:校验参数
        if(StringUtils.isBlank(dto.getContent()) || dto ==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2: 保存主表 wmnews| 对象的拷贝  | 判断type 无图自动
        WmNews wmNews =new WmNews();
        BeanUtils.copyProperties(dto,wmNews);
        if(WM_NEWS_TYPE_AUTO.equals(dto.getType())){
            wmNews.setType(null); //判断保存文章的封面状态
        }
       //2.1: 拆解封面图片
        if(dto.getImages()!=null && dto.getImages().size()>0){
            String imageStr = dto.getImages().toString().replace("[","")
                    .replace("]","").replace(fileServerUrl,"")
                    .replace(" ","");
            wmNews.setImages(imageStr);
        }
        this.saveWmNews(wmNews,isSubmit);

        //3: 维护文章和素材的关系表
        String content = dto.getContent();
        //JSONObject jsonObject = JSON.parseObject(content); //json字符串转json对象
        List<Map> list = JSON.parseArray(content, Map.class); //json 字符串转数组集合
        //提取文章内容中的图片
        List<String> imagetList = this.ectractUrlInfo(list);

        //3.1: 处理图片和素材库 | 内容图片是不是素材库中的
        if(isSubmit==1 && imagetList.size()>0){
            ResponseResult responseResult = saveRelativeInfo(imagetList, wmNews.getId());// 图片集合  文章id
            if(responseResult!=null && responseResult.getCode()!=0){
                return responseResult;
            }
        }


        //4:设置封面
        if(isSubmit==1){
            ResponseResult responseResult = saveRelativeInfoForCover(dto, imagetList, wmNews);
            if(responseResult!=null && responseResult.getCode()!=0){
                return responseResult;
            }
        }

        //保存文章成功后把文章id放到消息队列
        if(isSubmit==1){
            kafkaTemplate.send("wmnews_submit",JSON.toJSONString(wmNews.getId()));
        }

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    private ResponseResult saveRelativeInfoForCover(WmNewsDto dto,List<String> imageList,WmNews wmNews){
        List<String> images = dto.getImages();

        //设置封面规则
        if(dto.getType().equals(WM_NEWS_TYPE_AUTO)){
            //内容中的图片数量小于等于2  设置为单图
            if (imageList.size() > 0 && imageList.size() <= 2) {
                wmNews.setType(WM_NEWS_SINGLE_IMAGE);
                images = imageList.stream().limit(1).collect(Collectors.toList());
            } else if (imageList.size() > 2) {
                //如果内容中的图片大于2 则设置为多图
                wmNews.setType(WM_NEWS_MANY_IMAGE);
                images = imageList.stream().limit(3).collect(Collectors.toList());
            } else {
                //内容中没有图片，则是无图
                wmNews.setType(WM_NEWS_NONE_IMAGE);
            }
        }

        if(images!=null && images.size()>0){
            String imageStr = images.toString().replace("[","")
                    .replace("]","").replace(fileServerUrl,"")
                    .replace(" ","");
            wmNews.setImages(imageStr);
        }

        updateById(wmNews);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    private ResponseResult saveRelativeInfo(List<String> imagetList,Integer newsId ){
        //1:查看内容中的图片是不是素材库中的
        QueryWrapper<WmMaterial> queryWrapper =new QueryWrapper<>();
        queryWrapper.lambda().in(WmMaterial::getUrl,imagetList);
        //queryWrapper.in("url",imagetList);
        queryWrapper.lambda().eq(WmMaterial::getUserId,WmThreadLocalUtils.getUser().getId());
        List<WmMaterial> materialList = wmMaterialMapper.selectList(queryWrapper);

        //2:过滤素材库中的图片暂存到新的集合
        List<Integer> materialsId = new ArrayList<>();
        if(materialList.size()>0){
            //2.1 数据转换  把单条数据转成map（k-url，v-id） 存储
            Map<String, Integer> map = materialList.stream().collect(Collectors.toMap(WmMaterial::getUrl, WmMaterial::getId));
            for(String urlStr:imagetList){
                Integer  materialId =map.get(urlStr);
                if(materialId==null){
                    //不是素材库的
                    return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID, "应用图片失效");
                }else{
                    //是素材库
                    materialsId.add(materialId);
                }
            }

            //批量保存文章和素材库关系表
            wmNewsMaterialMapper.saveRelationsByContent(materialsId,newsId,WM_NEWS_CONTENT_REFERENCE);
        }
      return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    private List<String> ectractUrlInfo(List<Map> list){
        List<String> imageList = new ArrayList<>();
        for(Map map :list){
            if(map.get("type").equals(WM_NEWS_TYPE_IMAGE)){
                String url = (String) map.get("value");
                imageList.add(url.replace(fileServerUrl,""));
            }
        }
        return imageList;
    }

    private void saveWmNews(WmNews wmNews,Short isSubmit){
        wmNews.setStatus(isSubmit);
        wmNews.setUserId(WmThreadLocalUtils.getUser().getId());
        wmNews.setCreatedTime(new Date());
        wmNews.setSubmitedTime(new Date());
        wmNews.setEnable((short) 1);
        if(wmNews.getId() ==null){
            //新增
            this.save(wmNews);
        }else{
            //修改  删除中间表  update  重新插入关系表走保存的逻辑
            LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper();
            queryWrapper.eq(WmNewsMaterial::getNewsId, wmNews.getId());
            wmNewsMaterialMapper.delete(queryWrapper);

            updateById(wmNews);
        }
    }

    @Override
    public ResponseResult findWmNewsById(Integer id) {
        if(id ==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        WmNews wmNews = getById(id);

        ResponseResult responseResult =ResponseResult.okResult(wmNews);
        //把图片服务器前缀地址赋值
        responseResult.setHost(fileServerUrl);
        return responseResult;
    }

    @Override
    public ResponseResult delNews(Integer id){
        if(id ==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //先删关系表  再删主表
        WmNews wmNews = getById(id);
        if(wmNews == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
        }
        //业务判断  发布的文章不能删除
        if(wmNews.getStatus().equals(WmNews.Status.PUBLISHED)){
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH,"文章不能执行删除");
        }

        QueryWrapper<WmNewsMaterial> queryWrapper =new QueryWrapper<>();
        queryWrapper.lambda().eq(WmNewsMaterial::getNewsId,id);

        //Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id);
        wmNewsMaterialMapper.delete(queryWrapper);

        //删除wmnews
        removeById(wmNews.getId());
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);

    }

    @Override
    public ResponseResult downOrUp(WmNewsDto dto) {
        //1:校验参数
        if(dto ==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //2：校验文章是否存在
        WmNews wmNews = getById(dto.getId());
        if(wmNews == null){
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"文章不存在");
        }

        //3：已经发布的文章不能操作上下架
        if(wmNews.getStatus().equals(WmNews.Status.PUBLISHED)){
            return ResponseResult.errorResult(AppHttpCodeEnum.NO_OPERATOR_AUTH,"文章不能执行上下架");
        }

        //4: 修改enable 状态  1：上架 0：下架
           //update wm_news set enable = ? where id=?
        update(Wrappers.<WmNews>lambdaUpdate().set(WmNews::getEnable,dto.getEnable()).eq(WmNews::getId,dto.getId()));

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    @Override
    public WmNews findByUserId(Long userId){
        QueryWrapper<WmNews> queryWrapper =new QueryWrapper<>();
        queryWrapper.lambda().eq(WmNews::getUserId,userId);
        return wmNewsMapper.selectOne(queryWrapper);
    }

    @Override
    public List<Integer> findRelease() {
        QueryWrapper<WmNews> queryWrapper =new QueryWrapper<>();
        queryWrapper.lambda().eq(WmNews::getStatus,8).lt(WmNews::getPublishTime,new Date());
        List<WmNews> wmNewsList = wmNewsMapper.selectList(queryWrapper);

        //stream 流处理集合
        List<Integer> list = wmNewsList.stream().map(WmNews::getId).collect(Collectors.toList());

//        List<Integer> list1 =new ArrayList<>();
//        for(WmNews wmNews :wmNewsList){
//            list1.add(wmNews.getId());
//        }

        return list;
    }

    @Override
    public ResponseResult findList(NewsAuthDto dto){

        if(dto ==null){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        dto.checkParam();

        List<WmNewsVo> wmNewsVoList = wmNewsMapper.findListAndPage(dto);
        int count = wmNewsMapper.findListCount(dto);

       ResponseResult responseResult =new PageResponseResult(dto.getPage(),dto.getSize(),count);
       responseResult.setData(wmNewsVoList);
       return responseResult;
    }

    @Override
    public WmNewsVo findById(Integer id){

        WmNews wmNews = getById(id);

        WmNewsVo wmNewsVo =new WmNewsVo();

        if(wmNews !=null && wmNews.getUserId()!=null){
            WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());

            BeanUtils.copyProperties(wmNews,wmNewsVo);

            if(wmUser!=null){
                wmNewsVo.setAuthorName(wmUser.getName());
            }
        }
      return wmNewsVo;
    }
}
